//
//  Emoticons.swift
//  emoticon模块代码
//
//  Created by rong on 15/7/9.
//  Copyright © 2015年 rong. All rights reserved.
//

import UIKit

/*
    emoticons.bundle  的根目录下 有个文件 emoticons.plist， 保存了  Package 表情包信息
     其中，packages是一个 字典的  数组，  字典中的id 对应分组路径的名称

     在id对应的分组路径中， 各自都包含有 info.plist文件
        group_name_cn ：分组名称
        emoticons：     保存的是表情信息数组
                code            UNICODE 编码字符串   （emoji表情包中有）
                chs             表情文字，发送给新浪微博服务器的文本内容
                png             表情图片，在 App 中进行图文混排使用的图片
*/

//表情包
class EmoticonPackage: NSObject {
    
    
    //！！！表情包单例
    static let packageList = EmoticonPackage.packages()

    init(id: String) {
        self.id = id
    }
    
    //表情路径
    var id: String?
    //分组名称
    var groupName: String?
    //表情数组
    var emoticons: [Emoticon]?
    
    //加载表情数组包
    class func packages() -> [EmoticonPackage] {
        
        var list = [EmoticonPackage]()
        
        //  先设置  最近使用的表情包
        let p = EmoticonPackage(id: "")
        p.groupName = "最近"
        p.appendEmptyEmoticons()
        list.append(p)
        
        //取到 packages 数组
        let path = NSBundle.mainBundle().pathForResource("emoticons.plist", ofType: nil, inDirectory: "Emoticons.bundle")!
        let dict = NSDictionary(contentsOfFile: path)!
        let array = dict["packages"] as! [[String: AnyObject]]
        
        //实例化数组
        //emoticons ＝ [Emoticon]()
        
        //遍历 packages 数组
        for d in array {
          //print(d["id"])
            let p = EmoticonPackage(id: d["id"] as! String)
            p.loadEmoticons()
            
            p.appendEmptyEmoticons()
            list.append(p)
        }
        
        return list
    }
    
    //加载对应的表情数组
    private func loadEmoticons() {
        print(plistPath())
        
        //emoticons ＝ [Emoticon]()
        
        let dict = NSDictionary(contentsOfFile: plistPath())!
        
        //分组名
        groupName = dict["group_name_cn"] as? String
        let array = dict["emoticons"] as! [[String: String]]
        
        //实例化表情数组
        emoticons = [Emoticon]()
        
        //加载表情数组，遍历数组
        var index = 0
        for d in array {
            emoticons?.append(Emoticon(id: id, dict: d))
            index++
            if index == 20 {
                emoticons?.append(Emoticon(removeBtn: true))
                index = 0
            }
        }
    }
    
    //追加空白按钮，也就是追加空的数据模型
    private func appendEmptyEmoticons() {
        if emoticons == nil {
            //return,  为了第一个界面：最近使用的表情，改成下面的
            emoticons = [Emoticon]()
        }
        
        let count = emoticons!.count % 21
        if count > 0 || emoticons!.count == 0 {
            for _ in count..<20 {
                emoticons?.append(Emoticon(removeBtn: false))
            }
            //最后再追加一个删除按钮
            emoticons?.append(Emoticon(removeBtn: true))
        }
    }
    
    //添加 最近使用过的表情 
    func addRecentUseEmoticon(emoticon: Emoticon) {
        
       // let recentEmoticon = emoticons![0]
        // 判断数组中是否包含改表情
        let isContain = emoticons!.contains(emoticon)
        if !isContain {
            //如果没有，将表情添加到 “最近使用” 数组
            emoticons?.append(emoticon)
        }
        
        //根据times对数组进行排序，  删除末尾记录
        var result = emoticons!
        result = result.sort{ $0.times > $1.times }
        
//        if !isContain {
//            result.removeLast()
//        }
        
        //重新设置表情数组
        emoticons = result
    }
    
    class func emoticonAttributeString(string: String, font: UIFont) -> NSAttributedString? {
        // 目标： “我[爱你]到[崩溃]了！” -> 带表情的属性字符串
        // 1. 查找表情
        // 2. 提取表情字符串 － 正则表达式
        /*
        我[爱你]到[崩溃]了
        {1,4}  {6,4}
        */
        
        //let string = "我[爱你]到[崩溃]了！"
        
        // [] 是正则表达式保留字，在使用时，需要使用转义 \\两个斜杠
        let pattern = "\\[.*?\\]"
        
        do {
            // 选项：DotMatchesLineSeparators， 匹配 “.”点
            let regex = try NSRegularExpression(pattern: pattern, options: NSRegularExpressionOptions.DotMatchesLineSeparators)
            
            // matchesInString 是匹配多个，一个字符串中可能有多个 ［］, 返回的是一个数组
            let checkResults = regex.matchesInString(string, options: NSMatchingOptions(rawValue: 0), range: NSRange(location: 0, length: string.characters.count))
            /*
            func matchesInString(string: String, options: NSMatchingOptions, range: NSRange) -> [NSTextCheckingResult]
            次函数返回值是一个必选项，肯定不会为nil， 所以下面的判断有问题
            即便是 查找的东西，没有，也不会返回 nil,  会返回  空数组，  []
            */
            //if checkResults != nil {   print("哈哈哈哈哈  \(checkResults)")
            
            //取得 查找到的 结果的 计数
            var count = checkResults.count
            
            //先把原来的字符串，转成 可变的 属性字符串
            let strM = NSMutableAttributedString(string: string)
            
            
            /*遍历结果 查找到的结果是两个NSRange {1,4} {6,4}
            找到了这两个range之后，就开始替换
            方案1:  顺序替换   "我[爱你]到[崩溃]了！" ＝＝》 "我[爱你的属性图片]到[崩溃]了！"
            会发现替换完第一个后，第二个没法替换， {6,4}已经没法使用
            方案2:  倒序替换，可以使用
            */
            
            while count > 0 {
                //获取匹配结果
                let result = checkResults[--count]
                
                /*  打印结果： print(result)
                <NSSimpleRegularExpressionCheckingResult: 0x7f921861c6f0>{6, 4}{<NSRegularExpression: 0x7f9218626990> \[.*?\] 0x8}
                <NSSimpleRegularExpressionCheckingResult: 0x7f921862d3c0>{1, 4}{<NSRegularExpression: 0x7f9218626990> \[.*?\] 0x8}*/
                
                //取出range
                let r = result.rangeAtIndex(0)
                //print(r)  打印结果就是 (6,4) (1,4)  倒序
                
                //根据range，取出子串  ,swift的方法 string.substringWithRange(<#T##aRange: Range<Index>##Range<Index>#>) 不好使
                let subStr = (string as NSString).substringWithRange(r)
                // print(subStr) 打印结果  [崩溃]  [爱你]
                
                //取出字符串之后，就调用下面的函数（查找指定字符串对应的表情）
                //emoticon!.chs ==> [崩溃]     emoticon!.imgPath  ===> 崩溃表情的 图片的路径
                if let emoticon = emotionWithString(subStr) {
                    
                    //根据 emoticon 获得属性字符串
                    // 之前写过一个函数
                    //class func emoticonString(emoticon: Emoticon, font: UIFont) -> NSAttributedString
                    //传入一个 emoticon，还有字体，返回一个  属性字符串
                    
                    let attrStr = EmoticonAttachment.emoticonString(emoticon, font: font)
                    //拿到属性字符串之后，在拼接原来的属性字符串
                    //替换文本
                    strM.replaceCharactersInRange(r, withAttributedString: attrStr)
                }
            }
            return strM
            
            //textLabel.attributedText = strM //结果就是文本和图片并存
            //全部替换完成后，打印一下结果: print(strM)
            /*
            我{
            }￼{
            NSAttachment = "<\U00c2\U221e\U00dc\U00cb\U00b0\U00ae\U00ca\U00c9\U00d6\U00ca\U00f1\U00e1\U00c2\U2260\U00f3\U00cb\U03a9\U00a8\U00ca\U00e7\U00a2\U00ca\U00e0\U00ea\U00cb\U00b0\U00ae\U00ca\U00c9\U00d6\U00c2\U2260\U00f3\U00c1\U00a8\U00b6\U2030\U220f\U2264.EmoticonAttachment: 0x7f93a9e23520>";
            NSFont = "<UICTFont: 0x7f93a9f57f50> font-family: \".SFUIText-Regular\"; font-weight: normal; font-style: normal; font-size: 18.00pt";
            }到{
            }￼{
            NSAttachment = "<\U00c2\U221e\U00dc\U00cb\U00b0\U00ae\U00ca\U00c9\U00d6\U00ca\U00f1\U00e1\U00c2\U2260\U00f3\U00cb\U03a9\U00a8\U00ca\U00e7\U00a2\U00ca\U00e0\U00ea\U00cb\U00b0\U00ae\U00ca\U00c9\U00d6\U00c2\U2260\U00f3\U00c1\U00a8\U00b6\U2030\U220f\U2264.EmoticonAttachment: 0x7f93a9f58060>";
            NSFont = "<UICTFont: 0x7f93a9f57f50> font-family: \".SFUIText-Regular\"; font-weight: normal; font-style: normal; font-size: 18.00pt";
            }了！{
            }
            
            */
            
            
        } catch {
            
            print(error)
            return nil
        }
    }
    
    private class func emotionWithString(string: String) -> Emoticon? {
        
        var emoticon:Emoticon?
        
        for package in EmoticonPackage.packageList {
            
            emoticon = package.emoticons?.filter { $0.chs == string }.last
            
            if emoticon != nil {
                break
            }
        }
        
        //print("emoticonemoticonemoticon   ==> \(emoticon!.chs) \(emoticon!.imgPath)")
        return emoticon
    }
    
    //返回 Emoticons.bundle 的路径
    private func plistPath() -> String {
        return EmoticonPackage.bundlePath().stringByAppendingPathComponent(id!).stringByAppendingPathComponent("info.plist")
    }
    //返回 每个表情包的 info.plist 所在的路径
    private class func bundlePath() -> String {
        return NSBundle.mainBundle().bundlePath.stringByAppendingPathComponent("Emoticons.bundle")
    }
}


//表情模型,  id本身没有这个属性，是从外面传进来的
class Emoticon: NSObject {
    //表情路径
    var id: String?
    // 表情文字，发送给新浪微博服务器的文本内容
    var chs: String?
    // 表情图片，在 App 中进行图文混排使用的图片
    var png: String?
    //图片的完整路径
    var imgPath: String? {
        return png == nil ? nil : EmoticonPackage.bundlePath().stringByAppendingPathComponent(id!).stringByAppendingPathComponent(png!)
    }
    // emoji字符串
    var emoji: String?
    
    // unicode 编码字符串
    var code: String? {
        didSet {
            // 1. 扫描器，可以扫描指定字符串中特定的文字
            let scanner = NSScanner(string: code!)
            // 2. 扫描整数 Unsafe`Mutable`Pointer 可变的指针，要修改参数的内存地址的内容
            var result: UInt32 = 0
            scanner.scanHexInt(&result)
            
            // 3. 生成字符串：UNICODE 字符 -> 转换成字符串
            emoji = "\(Character(UnicodeScalar(result)))"

        }
    }
    
    // 是否是删除按钮
    var isRemoveBtnFlag = false
    
    // 为了记录最近使用表情用的,  记录用户使用次数
    var times = 0
    
    init(removeBtn: Bool) {
        //super.init()
        
        isRemoveBtnFlag = removeBtn
    }
    
    //做字典转模型
    init(id: String?, dict: [String:String]) {
        super.init()
        
        self.id = id
        
        //！！！如果 字典中有属性，而模型中没有这个属性，调用这个方法就会报错
        setValuesForKeysWithDictionary(dict)
    }
    
    // 只要重写这个方法，就不会发生上面说的问题，会自动过滤掉 模型中没有的属性
    override func setValue(value: AnyObject?, forUndefinedKey key: String) {
        print(key)
    }
}

